# 高阶函数
import functools
from functools import reduce

# 变量可以指向函数 => 函数本身可以赋值给变量
# abs 求绝对值
print(abs)
print(abs(-10))

# 函数名也是变量 => 该函数可以指向其他变量
# abs = 10
# abs(-10)
# 函数可以作为传参

# map/reduce
# map接收两个参数，一个是函数，一个是Iterator
l = list(map(str, [1, 2, 3, 4, 5, 6]))
print(l)


# reduce 必须接受两个参数，一个是函数，一个是Iterable
def fn(x, y):
    return x * 10 + y


reduce(fn, [1, 3, 5, 7, 9])


# filter 过滤  返回的是Iterator,可以用list函数获取所有结果并返回list结果
def odd(n):
    return n % 2 == 1


print(list(filter(odd, [1, 2, 3, 4, 5, 6, 7, 8, 9])))


# sorted 排序,高阶函数，可以接收一个key函数来实现自定义排序，例如按绝对值大小
print(sorted([12, 43, 23, 6, -5, -50]))
print(sorted([12, 43, 23, 6, -5, -50], key=abs))
# 字符串按照 ASCLL的大小比较
print(sorted(["bob", "about", "Zoo", "Credit"]))
print(sorted(["bob", "about", "Zoo", "Credit"], key=str.lower))  # 忽略大小写
print(
    sorted(["bob", "about", "Zoo", "Credit"], key=str.lower, reverse=True)
)  # 反转排序
L = [("Bob", 75), ("Adam", 92), ("Bart", 66), ("Lisa", 88)]


def byName(t):
    return t[0]


def byScore(s):
    return s[1]


L2 = sorted(L, key=byName)
L3 = sorted(L, key=byScore)
print(L2, L3)


# 返回函数，函数作为结果返回
# 闭包，内层函数引用了外层函数的局部变量
# nonlocal 声明该变量不是当前函数的局部变量
def inc():
    x = 0

    def fn():
        # nonlocal x
        return x + 1

    return fn


f = inc()


# 匿名函数 关键字 lambda 表示匿名函数，冒号前面的x表示函数参数
# 场景简单情况下使用lambda
list(
    map(
        lambda x: x * x,
        [
            1,
            2,
            3,
            4,
            5,
            6,
        ],
    )
)
print(list(filter(lambda x: x % 2 == 1, range(1, 20))))


# 装饰器 decorator  函数对象有一个 __name__ 属性（前后各两个下划线）为函数的名称
def log(func):
    def wrapper(*args, **kw):
        print("call %s():" % func.__name__)
        return func(*args, **kw)

    return wrapper


def log1(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kw):
            print("%s %s():" % (text, func.__name__))
            return func(*args, **kw)

        return wrapper

    return decorator


@log1("这个是")
def fo():
    print(1)


fo()


# 偏函数，函数参数太多需要简化时，使用functools.partial可以创建一个新的函数
int2 = functools.partial(int, base=2)
print(int2("1000000"))
max2 = functools.partial(max, 10)  # 会把10加到 *args中
print(max2(5, 9, 6))
